/*
 * Copyright 2024 LinQingYing. and contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of this source code is governed by the Apache License 2.0,
 * which allows users to freely use, modify, and distribute the code,
 * provided they adhere to the terms of the license.
 *
 * The software is provided "as-is", and the authors are not responsible for
 * any damages or issues arising from its use.
 *
 */

package com.linqingying.cangjie.psi

import com.google.common.collect.Lists
import com.linqingying.cangjie.lexer.CjTokens
import com.linqingying.cangjie.psi.stubs.CangJieUserTypeStub
import com.linqingying.cangjie.psi.stubs.elements.CjStubElementTypes
import com.intellij.lang.ASTNode

class CjUserType : CjElementImplStub<CangJieUserTypeStub >, CjTypeElement {
    constructor(node: ASTNode) : super(node)

    constructor(stub: CangJieUserTypeStub) : super(stub, CjStubElementTypes.USER_TYPE)

    override fun <R, D> accept(visitor: CjVisitor<R, D>, data: D?): R {
        return visitor.visitUserType(this, data)
    }

    val typeArgumentList: CjTypeArgumentList?
        get() = getStubOrPsiChild(CjStubElementTypes.TYPE_ARGUMENT_LIST)

    val typeArguments: List<CjTypeProjection>
        get() {
            val typeArgumentList = typeArgumentList
            return typeArgumentList?.arguments ?: emptyList()
        }

    override fun toString(): String {
        return node.elementType.toString()
    }

    override val typeArgumentsAsTypes: List<CjTypeReference>
        get() {
            val result: MutableList<CjTypeReference > =
                Lists.newArrayList()
            for (projection in typeArguments) {
                projection.typeReference?.let { result.add(it) }
            }
            return result
        }

    @get:IfNotParsed
    val referenceExpression: CjSimpleNameExpression?
        get() = getStubOrPsiChild(CjStubElementTypes.REFERENCE_EXPRESSION)

    val qualifier: CjUserType?
        get() = getStubOrPsiChild(CjStubElementTypes.USER_TYPE)

    /**
     * 保留除该USER_TYPE以外指定数量的psi元素
     * 例如 USER_TYPE = a.b.c; size = 1
     * 保留 b.c
     *
     * @param size
     */
    fun deleteQualifier(size: Int) {
        if (size <= 0) {
            deleteQualifier()
        }
        val qualifier = qualifier

        qualifier?.deleteQualifier(size - 1)
    }

    fun deleteQualifier() {
        val qualifier = checkNotNull(qualifier)
        val dot = checkNotNull(findChildByType(CjTokens.DOT))
        qualifier.delete()
        dot.delete()
    }

    val referencedName: String?
        get() {
            val referenceExpression = referenceExpression
            return referenceExpression?.referencedName
        }
}
